﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.Text;
using System.Xml;
//using System.Drawing;
using RH.Common.Extensions;
using RH.Common.Xml;
using RH.Domain;
using RH.Web.ViewModels;
using RH.Web.Utility;
using AutoMapper;
using RH.Web.ViewModels.UtilityModels;
using RH.Search;

namespace RH.Web.Areas.Private.Controllers
{
    [Authorize(Roles = "Company Admin,Company User,Admin")]
    [ValidateInput(false)]
    public class ProductController : BaseController
    {
        private AppEntities _Context = null; //new AppEntities();
        private EntityRepository _Repository = null;

        #region Constructors
        public ProductController()
        {
            _Context = new AppEntities();
            _Repository = new EntityRepository(_Context);
        }

        public ProductController(UserViewModel currentUser)
            : base(currentUser)
        {
        }
        #endregion

        #region Action Methods

        public ActionResult Index()
        {
            return RedirectToAction("List");
        }

        /// <summary>
        /// List of Active/Inactive products according to the Company
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult List(String id)
        {
            PagerConfig pagerConfig = new PagerConfig(id.ToInt() > 0 ? id.ToInt() : 1, ConfigReader.pageSize, 0);
            UtilityDAO dao = new UtilityDAO();
            DbParameter[] parameters = new[] { new DbParameter("@CompanyID", LoggedInUser.Company.ID) };
            int totalRecord = 0;
            System.Data.DataSet ds = dao.GetPagedData(DbObject.SP.GET_PAGED_PRODUCTS_BY_COMPANY, parameters, pagerConfig.PageNo, pagerConfig.PageSize, out totalRecord, true);

            pagerConfig.TotalRecord = totalRecord;
            ListConfig listConfig = new ListConfig(ds.Tables[0], pagerConfig);

            ActionHelper actionHelper = new ActionHelper(_Context);
            ViewData[AppConstants.ViewDataKeys.SUB_MODEL] = actionHelper.GetUserFavorites();

            return View(listConfig);
        }

        /// <summary>
        /// Gets a Product from Database to edit
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult Edit(int id = 0, String IsSaved = null, String IsAdded = null)
        {
            Product entity = null;
            if (id > 0)
            {
                entity = _Repository.GetProductByID(id);// _Context.Products.FirstOrDefault(P => P.ID == id);
                if (entity.CompanyID != LoggedInUser.Company.ID)
                    return base.RedirectToAccessDenied();
            }
            else
            {
                entity = new Product();
                entity.CompanyID = LoggedInUser.Company.ID;
            }

            ProductViewModel viewModel = Mapper.Map<Product, ProductViewModel>(entity);
            //ViewBag.ManufacturerList = new SelectList(_Context.Manufacturers.ToList(), "ID", "Name");
            TempData[AppConstants.ViewDataKeys.ADDED] = IsAdded;
            TempData[AppConstants.ViewDataKeys.SAVED] = IsSaved;
            return View(viewModel);
        }

        /// <summary>
        /// Saves Product Information into the Database
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Edit(ProductViewModel viewModel)
        {
            if (!ModelState.IsValid)
                return View(viewModel);

            ///Validate Unique Product Code and UPC
            bool hasValidationError = false;
            
            if (_Context.IsDuplicateProductUrl(viewModel.Name.ToSeoUrl(), viewModel.ID))
            {
                ModelState.AddModelError("Name", "Sorry! another property exists with same Title. Please choose another.");
                hasValidationError = true;
            }

            if (hasValidationError)
            {
                ViewData[AppConstants.ViewDataKeys.HAS_VALIDATION_ERROR] = true;
                //Prepare the lglValue XML and Store it in a hidden field with URL Encode.
                // Then the JS will call with this lglValue to regenerate the Dynamic Category UI.
                if (viewModel.CategoryID > 0)
                {
                    Product fallbackEntity = new Product();
                    fallbackEntity.ID = viewModel.ID;
                    fallbackEntity.CategoryID = viewModel.CategoryID;
                    StringBuilder searchData = new StringBuilder();
                    setDynamicProperties(fallbackEntity, ref searchData);
                    viewModel.ZGLPayloadXml = fallbackEntity.ZGLPayload;
                }
                return View(viewModel);
            }

            Product entity = null;
            DateTime createdOn = DateTime.Now;
            if (viewModel.ID == 0)
            {
                entity = new Product();
                _Context.AddToProducts(entity);
            }
            else
            {
                entity = _Repository.GetProductByID(viewModel.ID); //_Context.Products.Include("ProductImages").FirstOrDefault(P => P.ID == viewModel.ID);
                //createdOn = entity.Created;
            }

            viewModel.ProductUrl = viewModel.Name.ToSeoUrl();
            ///This Line is required to bypass the null settings to the ProductImages property of the entity
            ///This will force Automapper not to set null, which leads to a null reference exception during save.
            viewModel.ProductImages = new List<ProductImageViewModel>();

            entity = Mapper.Map<ProductViewModel, Product>(viewModel, entity);
            //entity.ProductUrl = entity.Name.ToSeoUrl();
            if (entity.ID == 0)
            {
                entity.CompanyID = LoggedInUser.Company.ID;
                entity.Created = DateTime.Now;
                if (ConfigReader.AutoApproveProduct)
                    entity.IsActive = true;
                else
                    entity.IsActive = false;
            }
            //entity.Created = createdOn;
            entity.Modified = DateTime.Now;

            //entity.ManufacturerID = 1;

            StringBuilder dynamicSearchData = new StringBuilder();
            setDynamicProperties(entity, ref dynamicSearchData);
            _Context.SaveChanges();
            ///Update Search Index in Lucene
            ProductIndexManager indexManager = new ProductIndexManager();
            indexManager.UpdateIndex(entity, "Private.ProductController.Edit");
            indexManager.CommitChanges();            
            indexManager.CloseWriter();  
            ///Refresh the Searcher Index
            ProductSearchManager.Reload();

            //return RedirectToAction("List");
            String url = String.Format("Edit/{0}", entity.ID);//viewModel.ID == 0 ? String.Format("Edit/{0}?IsAdded=True", entity.ID) : String.Format("Edit/{0}?IsSaved=True", entity.ID);
            if (viewModel.ID == 0)
                return RedirectToAction(url, new { IsAdded = "True" });

            return RedirectToAction(url, new { IsSaved = "True" });
        }

        /// <summary>
        /// Get List Of Product Added To Wish List
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        //public ActionResult MyFavorite(String id)
        //{
        //    int pageNo = id.ToInt() > 0 ? id.ToInt() : 1;
        //    int pageSize = ConfigReader.pageSize;

        //    UtilityDAO dao = new UtilityDAO();
        //    DbParameter[] parameters = new[] { 
        //    //new DbParameter("@CompanyID", 1), 
        //    //new DbParameter("@SearchKey", SearchKey),
        //    new DbParameter("@UserId",(SessionCache.CurrentUser==null)? 0 : SessionCache.CurrentUser.ID),
        //    };
        //    int totalRecord = 0;
        //    System.Data.DataSet ds =
        //        dao.GetPagedData(DbObject.SP.GET_PRODUCT_FROM_WISH_LIST,
        //        parameters, pageNo, pageSize, out totalRecord, true);
        //    ViewBag.PageNumber = pageNo;
        //    ViewBag.PageSize = pageSize;
        //    ViewBag.TotalRecord = totalRecord;
        //    ViewBag.DataSource = ds;
        //    ViewBag.SearchType = "WishList";
        //    //ViewBag.ShowEditLink = true;

        //    ViewModels.UtilityModels.PagerConfig pagerConfig = new ViewModels.UtilityModels.PagerConfig();
        //    pagerConfig.PageNo = pageNo;
        //    pagerConfig.PageSize = pageSize;
        //    //pagerConfig.TotalRecordMessage = "Total {0} Products Found";


        //    pagerConfig.UrlFormat = "/Product/WishList?id={0}";

        //    ViewBag.PagerConfig = pagerConfig;
        //    ViewBag.TotalRecord = pagerConfig.TotalRecord = totalRecord;

        //    return View();
        //}

        /// <summary>
        /// Generates the Product Entry Form According to the Selected Categry
        /// </summary>
        /// <param name="productID"></param>
        /// <param name="categoryID"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateInput(false)]
        public PartialViewResult GetDynamicUI(int productID, int categoryID, String lglValues = null)
        {
            Category category = _Context.Categories.Include("ZGL").FirstOrDefault(P => P.ID == categoryID);
            //if (category != null && !category.PropertyDefinition.IsEmpty())
            if (category != null && category.ZGL != null)
            {
                Product product = null;
                if (productID > 0)
                    product = _Repository.GetProductByID(productID); //_Context.Products.FirstOrDefault(P => P.ID == productID);
                else
                    product = new Product();

                ProductViewModel productViewModel = Mapper.Map<Product, ProductViewModel>(product);
                
                if (!lglValues.IsNullOrEmpty())
                    productViewModel.ZGLPayloadXml = lglValues.UrlDecode();
                //else
                //    productViewModel.ZGLPayloadXml = product.ZGLPayload;

                //productViewModel.ZGLModel = Mapper.Map<
                //WebUtil.MapZGL(productViewModel, category.PropertyDefinition);
                WebUtil.MapZGL(productViewModel, category.ZGL.Model);

                //ViewBag.Product = productViewModel;
                //ViewBag.Category = Mapper.Map<Category, CategoryViewModel>(category, new CategoryViewModel());
                return PartialView("_DynamicProductUI", productViewModel);
            }
            return null;
        }        

        /// <summary>
        /// Saves address with product reference
        /// </summary>
        /// <param name="viewModel"></param>
        /// <param name="productID"></param>
        /// <returns></returns>
        [HttpPost]
        public String SaveAddress(AddressViewModel viewModel, int productID)
        {
            Product product = _Repository.GetProductByID(productID);
            if (product != null)
            {
                Address entity = viewModel.ID > 0 ? _Context.Addresses.FirstOrDefault(P => P.ID == viewModel.ID) : new Address();
                if (viewModel.ID == 0)
                {
                    //entity.CreatedOn = DateTime.Now;
                    _Context.AddToAddresses(entity);
                }
                if (viewModel.ZipCode.IsEmpty())
                    entity.ZipCode = AppConstants.ValueOf.UNKNOWN; //viewModel.ZipCode = AppConstants.ValueOf.UNKNOWN;
                //entity = Mapper.Map<AddressViewModel, Address>(viewModel);
                
                if (SessionCache.CurrentUser != null)
                    entity.ModifiedBy = LoggedInUser.ID;
                //entity.ModifiedOn = DateTime.Now;
                
                entity.StreetAddress = viewModel.StreetAddress.UrlDecode();
                if (viewModel.LocationID > 0)
                    entity.LocationID = viewModel.LocationID;
                else
                    entity.LocationID = null;


                _Context.SaveChanges();
                if (viewModel.ID == 0)
                {
                    product.AddressID = entity.ID;
                    _Context.SaveChanges();
                }
                _Context.Refresh(System.Data.Objects.RefreshMode.StoreWins, entity);
                viewModel = Mapper.Map<Address, AddressViewModel>(entity);
                return String.Format("{0}[*ADDRESS_ID*]{1}", entity.ID, WebUtil.BuildAddressHtml(viewModel));
            }
            return String.Empty;
        }
        #endregion Action Methods

        #region Helper Methods
        /// <summary>
        /// This method is obsolete and no longer is use. Because Lucene indedx is being used for product search
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="dynamicSearchData"></param>
        /// <param name="isUpdateMode"></param>
        //private void updateSearchIndex(Product entity, String dynamicSearchData, bool isUpdateMode)
        //{
        //    ProductIndex index = _Context.ProductIndexes.FirstOrDefault(P => P.ProductID == entity.ID);
        //    if (index == null)
        //    {
        //        index = new ProductIndex();
        //        index.ProductID = entity.ID;
        //        _Context.AddToProductIndexes(index);
        //    }
        //    index.Name = entity.Name;
        //    index.Description = entity.Description;
        //    index.Model = entity.Model;
        //    index.XMLData = dynamicSearchData;
        //    _Context.SaveChanges();
        //}

        /// <summary>
        /// Set Dynamic Properties to Save in the Database as XML String
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="dynamicSearchableData">Sets the Dynamic Search Data During Searching Product Properties</param>        
        private void setDynamicProperties(Product entity, ref StringBuilder dynamicSearchableData)
        {
            Category category = _Context.Categories.FirstOrDefault(P => P.ID == entity.CategoryID);
            //if (category != null && !category.PropertyDefinition.IsEmpty())
            if (category != null && category.ZGL != null && !category.ZGL.Model.IsEmpty())
            {
                ZGLModel categoryLGL = XmlHelper.ToObject<ZGLModel>(category.ZGL.Model);
                if (categoryLGL == null)
                    entity.ZGLPayload = null;
                else
                {
                    ZGLPayload productLGL = new ZGLPayload();
                    productLGL.Property = new List<ZGLPayloadProperty>();
                    foreach (ZGLModelGroup group in categoryLGL.Group)
                    {
                        foreach (ZGLModelGroupProperty property in group.Property)
                        {
                            ZGLPayloadProperty productProperty = new ZGLPayloadProperty();
                            productProperty.Name = property.Name;
                            productProperty.Value = Request.Form[getDynamicControlName(property.Name)];
                            if (!productProperty.Value.IsEmpty())
                            {
                                if (property.IsSearchable.IsTrue())
                                    dynamicSearchableData.AppendFormat("{0}{1}", productProperty.Value, Environment.NewLine);

                                productProperty.Value = productProperty.Value.HtmlEncode();
                            }
                            //property.Value = Request.Form[getDynamicControlName(property.Name)];
                            productLGL.Property.Add(productProperty);
                        }
                    }
                    entity.ZGLPayload = XmlHelper.ToString<ZGLPayload>(productLGL);
                }
            }
        }

        private String getDynamicControlName(string elementName)
        {
            return String.Format("{0}{1}", AppConstants.UI.DYNAMIC_CONTROL_PREFIX, elementName);
        }

        #endregion Helper Methods
    }
}
